<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>OpenLayers with Geohash</title>
    <link rel="stylesheet" href="https://data.sunbt.ltd/lib/ol/v6.15.1/css/ol.css" type="text/css">
    <style>
        #map {
            width: 100%;
            height: 1000px;
        }
    </style>
</head>
<body>
<div id="map"></div>
<script src="https://data.sunbt.ltd/lib/ol/v6.15.1/build/ol.js"></script>
<script src="https://bundle.run/ngeohash@0.6.3"></script>
<script>
    var map = new ol.Map({
        target: 'map',
        layers: [
            new ol.layer.Tile({
                source: new ol.source.OSM()
            })
        ],
        view: new ol.View({
            center: ol.proj.fromLonLat([0, 0]),
            zoom: 2
        })
    });

    function getGeohashPrecision(zoomLevel) {
        if (zoomLevel <= 5) return 2;
        if (zoomLevel <= 10) return 4;
        if (zoomLevel <= 15) return 6;
        return 8;
    }

    function getGeohashRectangles(extent, precision) {
        var minLat = extent[1];
        var minLon = extent[0];
        var maxLat = extent[3];
        var maxLon = extent[2];

        var geohashRectangles = [];
        var stepLat = (maxLat - minLat) / Math.pow(2, precision); // 动态步长
        var stepLon = (maxLon - minLon) / Math.pow(2, precision); // 动态步长

        for (var lat = minLat; lat < maxLat; lat += stepLat) {
            for (var lon = minLon; lon < maxLon; lon += stepLon) {
                var hash = ngeohash.encode(lat, lon, precision);
                var bbox = ngeohash.decode_bbox(hash);
                geohashRectangles.push(bbox);
            }
        }
        return geohashRectangles;
    }

    function drawGeohashRectangles(map, rectangles) {
        var features = rectangles.map(function(bbox) {
            return new ol.Feature({
                geometry: new ol.geom.Polygon([[
                    ol.proj.fromLonLat([bbox[1], bbox[0]]),
                    ol.proj.fromLonLat([bbox[3], bbox[0]]),
                    ol.proj.fromLonLat([bbox[3], bbox[2]]),
                    ol.proj.fromLonLat([bbox[1], bbox[2]]),
                    ol.proj.fromLonLat([bbox[1], bbox[0]])
                ]])
            });
        });

        var vectorSource = new ol.source.Vector({
            features: features
        });

        var vectorLayer = new ol.layer.Vector({
            source: vectorSource,
            style: new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: 'red',
                    width: 1
                })
            })
        });

        // 清除之前的Geohash矩形图层
        map.getLayers().getArray()
            .filter(layer => layer instanceof ol.layer.Vector)
            .forEach(layer => map.removeLayer(layer));

        map.addLayer(vectorLayer);
    }

    map.on('moveend', function() {
        var extent = map.getView().calculateExtent(map.getSize());
        var zoomLevel = map.getView().getZoom();
        var precision = getGeohashPrecision(zoomLevel);
        var geohashRectangles = getGeohashRectangles(ol.proj.transformExtent(extent, 'EPSG:3857', 'EPSG:4326'), precision);
        drawGeohashRectangles(map, geohashRectangles);
    });
</script>
</body>
</html>
